package cn.qingyun.gis.modules.scenes.kafka;

import cn.hutool.json.JSONUtil;
import cn.qingyun.gis.exception.CommonException;
import cn.qingyun.gis.modules.scenes.entity.PoiScenario;
import cn.qingyun.gis.modules.scenes.entity.PoiScenarioProofread;
import cn.qingyun.gis.modules.scenes.entity.PoiUpdateLog;
import cn.qingyun.gis.modules.scenes.entity.UniAddrRegion;
import cn.qingyun.gis.modules.scenes.mapper.PoiUpdateLogMapper;
import cn.qingyun.gis.modules.scenes.mapper.UniAddrRegionMapper;
import cn.qingyun.gis.modules.scenes.request.PoiInsertRequest;
import cn.qingyun.gis.modules.scenes.service.IPoiScenarioProofreadService;
import cn.qingyun.gis.modules.scenes.service.IPoiScenarioService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Lists;
import org.locationtech.jts.io.WKTReader;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Set;

@Slf4j
@Controller
@RequestMapping("/app/scenes/")
//@Component
//@ConditionalOnProperty(prefix = "qingyun.kafka", name = "enabled", havingValue = "true")
public class KafkaConsumer {

    @Resource
    private IPoiScenarioService poiScenarioService;

    @Resource
    private UniAddrRegionMapper uniAddrRegionMapper;
    @Resource
    private PoiUpdateLogMapper poiUpdateLogMapper;
    @Resource
    private IPoiScenarioProofreadService iPoiScenarioProofreadService;

    //@KafkaListener(topics = "order-scenes-insert", groupId = "gisSyncGroup")
    @Transactional(rollbackFor = Exception.class)
    @GetMapping("/test2")
    @DS("scenes_offensive")
    public void consumeMessage(String message) {
        //TODO 未完成
        String str="{\n" +
                "    \"id\":\"666\",\n" +
                "    \"poiId\":\"test\",\n" +
                "    \"poiName\":\"济南博通科技园C区\",\n" +
                "    \"poiLng\":117.164186,\n" +
                "    \"poiLat\":36.95136,\n" +
                "    \"cityAdcode\":\"370100\",\n" +
                "    \"districtAdcode\":\"370115\",\n" +
                "    \"multiAddrChn\":\"银河路与永康街交叉口东南340米\",\n" +
                "    \"categoryIds\":\"120100\",\n" +
                "    \"categoryNames\":\"商务住宅;产业园区;产业园区\",\n" +
                "    \"telephone\":\"13212341234\",\n" +
                "    \"address\":\"山东省济南市济阳区济北街道银河路济南博通科技园C区\",\n" +
                "    \"type\":\"产业园区\",\n" +
                "    \"points\":\"POINT(117.164186 36.95136)\",\n" +
                "    \"updateTime\":\"2024-04-30 15:30:00\",\n" +
                "    \"createTime\":\"2024-04-30 15:30:00\",\n" +
                "    \"belongBuildId\":\"B0H6PRRX5O\",\n" +
                "    \"isBuild\":1,\n" +
                "    \"aoi\":\"MULTIPOLYGON(((117.163541 36.951596,117.163541 36.951596,117.165666 36.951622,117.165537 36.950704,117.163531 36.950627,117.16352 36.950713,117.163541 36.951596)))\"\n" +
                "}";
        PoiInsertRequest request=null;
        try {
//            log.debug("Received message: " + message);
            request = JSONUtil.toBean(str, PoiInsertRequest.class);
            //验证相关字段是否有空值情况
            ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
            Validator validator = factory.getValidator();
            Set<ConstraintViolation<PoiInsertRequest>> violations = validator.validate(request);
            if (!violations.isEmpty()) {
                ArrayList<String> messageList = Lists.newArrayList();
                violations.forEach(entity->{
                    String messageError = entity.getMessage();
                    messageList.add(messageError);
                });
                log.debug("新增数据字段有空值{}",messageList.toString());
                saveLog(JSONUtil.toJsonStr(request),messageList.toString(),3,false,null,null);
                return;
            }
            PoiScenario poiScenario = new PoiScenario();
            BeanUtils.copyProperties(request,poiScenario);
            if (StringUtils.isNotEmpty(request.getPoints())){
                poiScenario.setPoints(new WKTReader().read(request.getPoints()));
            }
            if (StringUtils.isNotEmpty(request.getAoi())){
                poiScenario.setAoi(new WKTReader().read(request.getAoi()));
            }
            QueryWrapper<UniAddrRegion> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().select(UniAddrRegion::getId,UniAddrRegion::getCode,UniAddrRegion::getParentCode,UniAddrRegion::getLevel,
                    UniAddrRegion::getName,UniAddrRegion::getParentName,UniAddrRegion::getState)
                .eq(UniAddrRegion::getLevel, 4).ne(UniAddrRegion::getState,-1)
                .apply("st_within(st_geometryfromtext({0}, 4326), wkt)", request.getPoints())
                .last("LIMIT 1");
            //1.点落变化的网格，取网格和区县数据
            UniAddrRegion uniAddrRegion = uniAddrRegionMapper.selectOne(queryWrapper);
            //落上网格数据
            if (uniAddrRegion!=null){
                if (StringUtils.isEmpty(uniAddrRegion.getCode())){
                    log.debug("{}数据，网格编码是空值",request.getPoiId());
                    saveLog(JSONUtil.toJsonStr(request),"所落的网格编码是空值",3,false,request.getPoiId(),null);
                    return;
                }
                if (StringUtils.isEmpty(uniAddrRegion.getParentCode())){
                    log.debug("网格编码{}，对应的区县编码为空值！",uniAddrRegion.getParentCode());
                    saveLog(JSONUtil.toJsonStr(request),"所落的区县编码是空值",3,false,request.getPoiId(),null);
                    return;
                }
                //根据区县取地市数据
                UniAddrRegion regionCity = uniAddrRegionMapper.getRegionCity(uniAddrRegion.getParentCode());
                if (regionCity==null || StringUtils.isEmpty(regionCity.getParentCode())){
                    log.debug("网格编码{}，对应的地市编码为空值！",uniAddrRegion.getCode());
                    saveLog(JSONUtil.toJsonStr(request),"所落的地市编码是空值",3,false,request.getPoiId(),null);
                    return;
                }
                poiScenario.setGridCode(uniAddrRegion.getCode());
                poiScenario.setGridName(uniAddrRegion.getName());
                poiScenario.setRegionDisCode(uniAddrRegion.getParentCode());
                poiScenario.setRegionDis(uniAddrRegion.getParentName());
                poiScenario.setRegionCityCode(regionCity.getParentCode());
                poiScenario.setRegionCity(regionCity.getParentName());
            }else {
                //未落上网格数据，取离该点最近poi点的市区网格码
                PoiScenario nearestPoiData = poiScenarioService.getNearestPoiData(request.getPoints());
                poiScenario.setGridCode(nearestPoiData.getGridCode());
                poiScenario.setGridName(nearestPoiData.getGridName());
                poiScenario.setRegionDisCode(nearestPoiData.getRegionDisCode());
                poiScenario.setRegionDis(nearestPoiData.getRegionDis());
                poiScenario.setRegionCityCode(nearestPoiData.getRegionCityCode());
                poiScenario.setRegionCity(nearestPoiData.getRegionCity());
            }
            //2.落微网格
            UniAddrRegion microGrid = uniAddrRegionMapper.matchMicroGrid(request.getPoints());
            if (microGrid!=null){
                poiScenario.setMicroGridCode(microGrid.getCode());
                poiScenario.setMicroGridName(microGrid.getName());
            }
            //查询库里是否有该条数据
            LambdaQueryWrapper<PoiScenario> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(PoiScenario::getPoiId,poiScenario.getPoiId());
            PoiScenario poiScenarioOld = poiScenarioService.getBaseMapper().selectOne(wrapper);
            if (poiScenarioOld!=null){
                log.debug("查询到的老数据{}", poiScenarioOld);
                poiScenario.setId(poiScenarioOld.getId());
                poiScenario.setKwState(poiScenarioOld.getKwState());
                poiScenario.setKwMixState(poiScenarioOld.getKwMixState());
                poiScenario.setUpdateTime(poiScenarioOld.getUpdateTime());
                //先删除
                LambdaQueryWrapper<PoiScenario> deleteWrapper = new LambdaQueryWrapper<>();
                deleteWrapper.eq(PoiScenario::getPoiId,poiScenarioOld.getPoiId()).eq(PoiScenario::getRegionCityCode,poiScenarioOld.getRegionCityCode());
                int delete = poiScenarioService.getBaseMapper().delete(deleteWrapper);
                saveLog(poiScenarioOld.toString(),"老数据删除成功",3,true,request.getPoiId(),1);
                log.debug("删除{}老数据的结果{}", poiScenarioOld, delete);
                //如果地市编码变化，需要更新记录表里的地市编码字段
                if (!poiScenarioOld.getRegionCityCode().equals(poiScenario.getRegionCityCode())){
                    UpdateWrapper<PoiScenarioProofread> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.lambda().set(PoiScenarioProofread::getRegionCityCode, poiScenario.getRegionCityCode()).eq(PoiScenarioProofread::getPoiScenarioId, poiScenarioOld.getId());
                    boolean update = iPoiScenarioProofreadService.update(updateWrapper);
                    saveLog(poiScenario.getRegionCityCode(),"更新摸排记录表地市编码,旧的编码为,"+poiScenarioOld.getRegionCityCode(),3,update,poiScenarioOld.getId(),null);
                    log.debug("更新记录表地市编码成功");
                }
            }
            //新增数据
            boolean result = poiScenarioService.save(poiScenario);
            saveLog(JSONUtil.toJsonStr(request),"数据新增成功",3,true,request.getPoiId(),1);
            log.debug("新增的数据进行插入结果{}", result);
        } catch (Exception e) {
            log.debug("数据插入失败{}",request);
            saveLog(JSONUtil.toJsonStr(request),e.getMessage(),3,false,null,null);
            throw new CommonException("数据插入失败！" + e.getMessage());
        }
    }
    /**
     * 保存操作日志
     *
     * @param message 信息
     * @param type    日志类型
     * @param flag    是否成功标识
     * @param code    操作区划码
     * @param count   操作的个数
     */
    private void saveLog(String content,String message, Integer type, Boolean flag, String code, Integer count) {
        PoiUpdateLog poiUpdateLog = new PoiUpdateLog();
        poiUpdateLog.setCreatTime(new Date());
        poiUpdateLog.setSuccess(flag);
        poiUpdateLog.setSuccessCount(count);
        poiUpdateLog.setCode(code);
        poiUpdateLog.setType(type);
        poiUpdateLog.setMessage(message);
        poiUpdateLog.setContent(content);
        poiUpdateLogMapper.insert(poiUpdateLog);
    }
}
